﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Management;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Threading;
using FileSquirrel.Logic.XSD;
using FSquirrel.Helpers;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using FileSquirrel.Logic;
using FSquirrel.Properties;

namespace FSquirrel.ViewModel
{
    public class CopierViewModel : ViewModelBase
    {
        #region Declarations

        private LibraryDataSet RequestFile;

        public const string DiskSpaceOnDrivePropertyName = "DiskSpaceOnDrive";
        public const string TotalDiskSpacePropertyName = "TotalDiskSpace";
        public const string SpaceFreePropertyName = "SpaceFree";
        public const string CopyPathPropertyName = "CopyPath";
        public const string CurrentFilePropertyName = "CurrentFile";
        public const string RemovableDriveListPropertyName = "RemovableDriveList";
        public const string CurrentFilePercentagePropertyName = "CurrentFilePercentage";
        public const string IsCopyingPropertyName = "IsCopying";
        public const string CurrentFilePercentageTaskPropertyName = "CurrentFilePercentageTask";
        public const string CopyListCountPropertyName = "CopyListCount";
        public const string CopyListCapacityPropertyName = "CopyListCapacity";
        public const string IsNotCopyingPropertyName = "IsNotCopying";
        public const string RequestListPropertyName = "RequestList";
        public const string CopierVisibilityPropertyName = "CopierVisibility";
        public const string RequestFileNamePropertyName = "RequestFileName";

        private string _requestfilename = string.Empty;
        private Visibility _copiervisibility = Visibility.Collapsed;
        private ObservableCollection<LibraryDataSet.RequestListRow> _requestList = new ObservableCollection<LibraryDataSet.RequestListRow>();
        private bool _isnotcopying = false;
        private int _copylistcapacity = 0;
        private int _copylistcount = 0;
        private decimal _Currentfilepercentagetask;
        private bool _iscopying = false;
        private double _currentfilepercentage = 0.0;
        private ObservableCollection<string> _removabledrivelist = new ObservableCollection<string>();
        private string _currentfile = string.Empty;
        private string _copypath = string.Empty;
        private int _spacefree;
        private double _diskspaceondrive;
        private double _totaldiskspace;
        //private string _oldfilename;

        #endregion Declarations

        /// <summary>
        /// Initializes a new instance of the CopierViewModel class.
        /// </summary>
        public CopierViewModel()
        {


            PopulateRemovableDrives();

            BrowseCommand = new RelayCommand<object>(BrowseCopyLocation);
            GoCommand = new RelayCommand<object>(GoCopy);
            RemovableSelectionCommand = new RelayCommand<string>(RemovableDriveSelected);
            VisibilityCommand = new RelayCommand(DisplaySettings);

            CopyListCapacity = 0;
            CopyListCount = 0;

        }

        #region Commands

        public RelayCommand<object> BrowseCommand { get; private set; }

        public RelayCommand<object> GoCommand { get; private set; }

        public RelayCommand<string> RemovableSelectionCommand { get; private set; }
        public RelayCommand VisibilityCommand { get; private set; }

        #endregion Commands

        #region Properties

        public const string ShowCopyPropertyName = "ShowCopy";

        private bool _showcopy = false;


        public bool ShowCopy
        {
            get
            {
                return _showcopy;
            }

            set
            {
                if (_showcopy == value)
                {
                    return;
                }

                RaisePropertyChanging(ShowCopyPropertyName);
                _showcopy = value;
                RaisePropertyChanged(ShowCopyPropertyName);
            }
        }

        public int SpaceFree
        {
            get
            {
                return _spacefree;
            }

            set
            {
                if (_spacefree == value)
                {
                    return;
                }

                RaisePropertyChanging(SpaceFreePropertyName);
                _spacefree = value;
                RaisePropertyChanged(SpaceFreePropertyName);
            }
        }

        public double DiskSpaceOnDrive
        {
            get
            {
                return _diskspaceondrive;
            }

            set
            {
                if (_diskspaceondrive == value)
                {
                    return;
                }

                RaisePropertyChanging(DiskSpaceOnDrivePropertyName);
                _diskspaceondrive = value;
                RaisePropertyChanged(DiskSpaceOnDrivePropertyName);
            }
        }

        public double TotalDiskSpace
        {
            get
            {
                return _totaldiskspace;
            }

            set
            {
                if (_totaldiskspace == value)
                {
                    return;
                }

                RaisePropertyChanging(TotalDiskSpacePropertyName);
                _totaldiskspace = value;
                RaisePropertyChanged(TotalDiskSpacePropertyName);
            }
        }

        public string CopyPath
        {
            get
            {
                return _copypath;
            }

            set
            {
                if (_copypath == value)
                {
                    return;
                }

                RaisePropertyChanging(CopyPathPropertyName);
                _copypath = value;
                RaisePropertyChanged(CopyPathPropertyName);

                IsNotCopying = !string.IsNullOrEmpty(_copypath);
                DriveInfo di = new DriveInfo(_copypath);
                PopulateDiskIformation(di.Name);
            }
        }

        public string CurrentFile
        {
            get
            {
                return _currentfile;
            }

            set
            {
                if (_currentfile == value)
                {
                    return;
                }

                RaisePropertyChanging(CurrentFilePropertyName);
                _currentfile = value;
                RaisePropertyChanged(CurrentFilePropertyName);
            }
        }


        public string RequestFileName
        {
            get
            {
                return _requestfilename;
            }

            set
            {



                RequestFile = new LibraryDataSet();
                RequestFile.ReadXml(value);

                RequestList = new ObservableCollection<LibraryDataSet.RequestListRow>(RequestFile.RequestList);

                _Indexer.RequestFilesName = string.Format("{0}_RequestFrom_{0}", Settings.Default.LibraryName);

                RaisePropertyChanging(RequestFileNamePropertyName);
                _requestfilename = value;
                RaisePropertyChanged(RequestFileNamePropertyName);

                initializeCopy();
            }
        }

        private void initializeCopy()
        {
            ShowCopy = true;
            CopyListCapacity = RequestList.Count;
            CurrentFilePercentage = 0;
            CopyListCount = 0;

        }

        public ObservableCollection<string> RemovableDriveList
        {
            get
            {
                return _removabledrivelist;
            }

            set
            {
                if (_removabledrivelist == value)
                {
                    return;
                }


                RaisePropertyChanging(RemovableDriveListPropertyName);
                _removabledrivelist = value;
                RaisePropertyChanged(RemovableDriveListPropertyName);
            }
        }

        public double CurrentFilePercentage
        {
            get
            {
                return _currentfilepercentage;
            }

            set
            {
                if (_currentfilepercentage == value)
                {
                    return;
                }

                RaisePropertyChanging(CurrentFilePercentagePropertyName);
                _currentfilepercentage = value;
                RaisePropertyChanged(CurrentFilePercentagePropertyName);
            }
        }

        public bool IsCopying
        {
            get
            {
                return _iscopying;
            }

            set
            {
                if (_iscopying == value)
                {
                    return;
                }

                RaisePropertyChanging(IsCopyingPropertyName);
                _iscopying = value;
                RaisePropertyChanged(IsCopyingPropertyName);
                IsNotCopying = !IsCopying;
            }
        }

        public decimal CurrentFilePercentageTask
        {
            get
            {
                return _Currentfilepercentagetask;
            }

            set
            {
                if (_Currentfilepercentagetask == value)
                {
                    return;
                }

                RaisePropertyChanging(CurrentFilePercentageTaskPropertyName);
                _Currentfilepercentagetask = value;
                RaisePropertyChanged(CurrentFilePercentageTaskPropertyName);
            }
        }

        public int CopyListCount
        {
            get
            {
                return _copylistcount;
            }

            set
            {
                if (_copylistcount == value)
                {
                    return;
                }

                RaisePropertyChanging(CopyListCountPropertyName);
                _copylistcount = value;
                RaisePropertyChanged(CopyListCountPropertyName);
            }
        }

        public int CopyListCapacity
        {
            get
            {
                return _copylistcapacity;
            }

            set
            {
                if (_copylistcapacity == value)
                {
                    return;
                }

                RaisePropertyChanging(CopyListCapacityPropertyName);
                _copylistcapacity = value;
                RaisePropertyChanged(CopyListCapacityPropertyName);
            }
        }

        public bool IsNotCopying
        {
            get
            {
                return _isnotcopying;
            }

            set
            {
                if (_isnotcopying == value)
                {
                    return;
                }

                RaisePropertyChanging(IsNotCopyingPropertyName);
                _isnotcopying = value;
                RaisePropertyChanged(IsNotCopyingPropertyName);
                IsNotCopying = _requestList.Count > 0;
            }
        }

        public ObservableCollection<LibraryDataSet.RequestListRow> RequestList
        {
            get
            {
                return _requestList;
            }

            set
            {
                if (_requestList == value)
                {
                    return;
                }

                RaisePropertyChanging(RequestListPropertyName);
                _requestList = value;
                RaisePropertyChanged(RequestListPropertyName);
                RaisePropertyChanged("TotalSize");
            }
        }

        public int TotalSize
        {
            get
            {
                return (from dr in RequestList
                        select dr.Size).Sum();
            }
        }



        public Visibility CopierVisibility
        {
            get
            {
                return _copiervisibility;
            }

            set
            {
                if (_copiervisibility == value)
                {
                    return;
                }

                RaisePropertyChanging(CopierVisibilityPropertyName);
                _copiervisibility = value;
                RaisePropertyChanged(CopierVisibilityPropertyName);
                PopulateRemovableDrives();
            }
        }

        #endregion Properties

        #region Methods

        private void PopulateDiskIformation(string drivename)
        {
            foreach (DriveInfo drive in DriveInfo.GetDrives())
            {
                if (drive.IsReady && drive.Name == drivename)
                {
                    TotalDiskSpace = drive.TotalSize;
                    DiskSpaceOnDrive = drive.TotalSize - drive.AvailableFreeSpace;
                    SpaceFree = (int)((drive.AvailableFreeSpace / 1024) / 1024);
                    return;
                }
            }
        }

        private void PopulateRemovableDrives()
        {
            FileSizeConverter fsc = new FileSizeConverter();
            List<string> lstUSB = new List<string>();

            RemovableDriveList.Clear();

            using (ManagementObjectSearcher theSearcher = new ManagementObjectSearcher(
                 "SELECT * FROM Win32_DiskDrive WHERE InterfaceType='USB'"))
            {
                using (ManagementObjectCollection moc = theSearcher.Get())
                {
                    foreach (ManagementObject mo in moc)
                    {
                        foreach (ManagementObject b in mo.GetRelated("Win32_DiskPartition"))
                        {
                            foreach (ManagementBaseObject c in b.GetRelated("Win32_LogicalDisk"))
                                lstUSB.Add(c["Name"].ToString() + "\\");
                        }
                    }
                }
            }

            foreach (DriveInfo drive in DriveInfo.GetDrives())
            {
                if (drive.IsReady && lstUSB.Contains(drive.Name))
                {
                    int free = (int)((drive.TotalFreeSpace / 1024) / 1024);
                    RemovableDriveList.Add(string.Format("{0} | {1} Free", drive.Name, fsc.Convert(free, typeof(string), null, null)));
                }
            }
        }

        private void BrowseCopyLocation(object sender)
        {
            using (var dialog = new FolderBrowserDialog())
            {
                DialogResult result = dialog.ShowDialog();

                if (result == DialogResult.OK)
                {
                    CopyPath = dialog.SelectedPath;
                    FileInfo f = new FileInfo(CopyPath);
                    PopulateDiskIformation(Path.GetPathRoot(f.FullName));
                }
            }
        }

        private async void GoCopy(object sender)
        {
            var progress = new Progress<CopierEventArguments>();
            progress.ProgressChanged += progress_ProgressChanged;

            IsCopying = true;

            List<LibraryDataSet.RequestListRow> _tmp = new List<LibraryDataSet.RequestListRow>(RequestList);
            var CopyTask = Task.Factory.StartNew(() => cfewEngine.CopyFiles(_tmp, CopyPath, progress));
            await CopyTask;
            IsCopying = false;
            ShowCopy = false;
        }

        void progress_ProgressChanged(object sender, CopierEventArguments e)
        {
            if (!e.FileName.Equals("Done"))
            {
                CurrentFilePercentage = e.Percentage;
                //CopyListCapacity = e.Count;
                CopyListCount = e.Index + 1;
                CurrentFilePercentageTask = (decimal)CopyListCount / CopyListCapacity;
                if (e.FileName != CurrentFile && !string.IsNullOrEmpty(CurrentFile))
                {
                    var filerow = RequestList.First(t => t.Name == Path.GetFileNameWithoutExtension(CurrentFile));
                    RequestList.Remove(filerow);
                    RequestFile.RequestList.RemoveRequestListRow(filerow);
                }
                CurrentFile = e.FileName;
            }
            else
            {
                RequestList.Clear();
                RaisePropertyChanged("TotalSize");
                RequestFile.RequestList.Clear();
            }
            RequestFile.WriteXml(RequestFileName);
        }

        private void RemovableDriveSelected(string selection)
        {
            CopyPath = selection.Split('|')[0].Trim() + Path.GetFileNameWithoutExtension(RequestFileName);

        }


        private void DisplaySettings()
        {
            switch (CopierVisibility)
            {
                case Visibility.Visible:
                    CopierVisibility = Visibility.Collapsed;
                    break;
                case Visibility.Collapsed:
                    CopierVisibility = Visibility.Visible;
                    break;
            }
        }

        private CopyFileExWrapper cfewEngine = new CopyFileExWrapper();

        #endregion Methods

        private Indexer indexer;
        public Indexer _Indexer
        {
            get { return indexer ?? (indexer = new Indexer(Settings.Default.LibraryName, Settings.Default.LibraryDir)); }
        }
    }

}